﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Text;

namespace Bouyei.GeoCore.GeoParsers.Dbf
{
    public class DbfWriter : BaseFile
    {
        public DataTable dbfTable { get; private set; }

        public DbfWriter(string dbfFile, Encoding encoding)
            : base(dbfFile, encoding)
        {
            if (encoding == null)
                encoding = Encoding.GetEncoding(936);//GB2312
        }

        public override void Dispose()
        {
            base.Dispose();
        }

        public int Writer(DataTable table)
        {
            using (DbfFile dbfile = new DbfFile(PathName, encoding))
            {
                DbfHeader header = new DbfHeader(encoding);
                foreach (DataColumn col in table.Columns)
                {
                    AddColumnFrom(header, col.ColumnName, col.DataType);
                }
                header.NumRecords = table.Rows.Count;
                dbfile.Write(header);

                //rows
                foreach (DataRow dr in table.Rows)
                {
                    dbfile.Write(dr.ItemArray);
                }
                dbfile.WriteEndOfDbf();
                dbfile.Close();
            }
            return table.Rows.Count;
        }

        public int Writer<T>(List<T> list)
        {
            using (DbfFile dbfile = new DbfFile(PathName, encoding))
            {
                DbfHeader header = new DbfHeader(encoding);
                var pros = typeof(T).GetProperties(System.Reflection.BindingFlags.Public
                    | System.Reflection.BindingFlags.Instance);

                foreach (var p in pros)
                {
                    AddColumnFrom(header, p.Name, p.PropertyType);
                }
                header.NumRecords = list.Count;
                dbfile.Write(header);

                foreach (var item in list)
                {
                    object[] cols = new object[pros.Length];
                    for (int i = 0; i < cols.Length; ++i)
                    {
                        cols[i] = pros[i].GetValue(item, null);
                    }
                    dbfile.Write(cols);
                }
                dbfile.WriteEndOfDbf();
                dbfile.Close();

                return list.Count;
            }
        }

        private void AddColumnFrom(DbfHeader dbfHeader, string columnName, Type dataType)
        {
            char fieldType = DbfColumn.GetDbaseType(dataType);
            int fieldLength = 0;
            int decimalCount = 0;

            if (dataType == typeof(string))
            {
                fieldLength = 64;
                if (fieldLength > 254) fieldLength = 254;
                else if (fieldLength <= 0) fieldLength = 24;
            }
            else if (dataType == typeof(char))
            {
                fieldLength = 1;
            }
            else if (dataType == typeof(bool))
            {
                fieldLength = 1;
            }
            else if (dataType == typeof(short))
            {
                fieldLength = 4;
            }
            else if (dataType == typeof(int))
            {
                fieldLength = 8;
            }
            else if (dataType == typeof(long))
            {
                fieldLength = 16;
            }
            else if (dataType == typeof(DateTime))
            {
                fieldLength = 8;
            }
            else if (dataType == typeof(float))
            {
                fieldLength = 7;
                decimalCount = 3;
            }
            else if (dataType == typeof(double))
            {
                fieldLength = 17;
                decimalCount = 6;
            }
            else throw new Exception("not support data type");

            dbfHeader.AddColumn(columnName, fieldType, fieldLength, decimalCount);
        }
    }
}
